﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Windows.Controls.Primitives;
namespace InpValidator
{
	public abstract class ValidatorBase : DependencyObject
    {
        #region Событие инициализации
        private event RoutedEventHandler _Init;
        public event RoutedEventHandler Init
        {
            add 
            { 
                _Init += value;
                this.RaiseInit();
            }
            remove 
            {
                _Init -= value;
            }
        }
        protected void RaiseInit()
        {
            if (this._Init != null) this._Init(this, new RoutedEventArgs());
        }
        public bool InitHandlerExist
        {
            get
            {
                return this._Init != null;
            }
        }
        #endregion

        public ValidatorManager Manager { get; set; }
        public ValidatorType Type { get; set; }
        public ValidationType validationType { get; set; }
        public Control ElementToValidate { get; set; }
        public Panel LayoutRoot { get; set; }
		public string ErrorMessage { get; set; }

        public Style ValidStyle { get; set; }
        public Brush ValidBorderBrush { get; set; }
        public Brush ValidBackground { get; set; }
        public object ValidToolTip { get; set; }
        public Thickness ValidBorderThickness { get; set; }
		
        /// <summary>
        /// Вызов базового конструктора обязателен
        /// </summary>
		public ValidatorBase()
		{
			this.validationType = ValidationType.Validator;
		}

        /// <summary>
        /// Метод, который должен вызвать ValidatorService
        /// </summary>
        /// <param name="element"></param>
        public void Initialize(Control element)
        {
            ElementToValidate = element;

            this.ValidBackground = element.Background;
            this.ValidBorderBrush = element.BorderBrush;
            this.ValidToolTip = ToolTipService.GetToolTip(element);
            this.ValidBorderThickness = element.BorderThickness;
            this.ValidStyle = element.Style;

            ActivateValidationRoutine();
            this.Initialize();
        }

        /// <summary>
        /// Окружение устанавливается на странице, на которой расположен ValidatorManager
        /// </summary>
        /// <param name="UserControl"></param>
        /// <param name="manager"></param>
        public void SetEnvironment(Panel LayoutRoot, ValidatorManager manager)
        {
            this.LayoutRoot = LayoutRoot;
            this.Manager = manager;
        }

        /// <summary>
        /// Окружение устанавливается на странице, на которой расположен ValidatorManager
        /// </summary>
        /// <param name="UserControl"></param>
        /// <param name="dataForm"></param>
        /// <param name="manager"></param>
        public void SetEnvironment(Panel LayoutRoot, DataForm dataForm, ValidatorManager manager)
        {
            this.LayoutRoot = LayoutRoot;
            this.Manager = manager;
        }        

		/// <summary>
		/// Find the nearest UserControl up the control tree for the FrameworkElement passed in
		/// </summary>
		/// <param name="element">Control to validate</param>
        protected static FrameworkElement FindUserControl(FrameworkElement element)
		{
            return element.Parent as FrameworkElement;
		}

        protected void ControlNotValid()
        {
            this.ShowErrorToolTip();
        }

        protected void ControlValid()
        {
            this.HideErrorToolTip();
        }

        protected void ShowErrorToolTip()
        {
            Thickness thickness = new Thickness(2);
            SolidColorBrush brush = new SolidColorBrush(Color.FromArgb(255, 233, 80, 88));
            SolidColorBrush background = new SolidColorBrush(Color.FromArgb(255, 249, 226, 226));

            if (this.ValidStyle == null)
            {
                this.ElementToValidate.BorderThickness = thickness;
                this.ElementToValidate.BorderBrush = brush;
                this.ElementToValidate.Background = background;
            }
            else
            {
                Style style = new Style(this.ElementToValidate.GetType());
                style.Setters.Add(new Setter { Property = Control.BorderThicknessProperty, Value = thickness });
                style.Setters.Add(new Setter { Property = Control.BorderBrushProperty, Value = brush });
                style.Setters.Add(new Setter { Property = Control.BackgroundProperty, Value = background });
                this.ElementToValidate.Style = style;
            }

            // Формируем ToolTip
            StackPanel stackPanel = new StackPanel();
            stackPanel.Orientation = Orientation.Vertical;

            if(this.ValidToolTip is UIElement)
                stackPanel.Children.Add(this.ValidToolTip as UIElement);
            if (this.ValidToolTip is string)
                stackPanel.Children.Add(new TextBlock() { Text = this.ValidToolTip.ToString() });

            stackPanel.Children.Add(new TextBlock() { Text = this.ErrorMessage, FontWeight = FontWeights.Bold });

            ToolTipService.SetToolTip(this.ElementToValidate, stackPanel);
        }

        protected void HideErrorToolTip()
        {
            if (this.ElementToValidate.Style != null)
            {
                this.ElementToValidate.Style = this.ValidStyle;
            }
            else
            {
                this.ElementToValidate.BorderBrush = this.ValidBorderBrush;
                this.ElementToValidate.BorderThickness = this.ValidBorderThickness;

                if (this.ValidBackground != null)
                    this.ElementToValidate.Background = this.ValidBackground;
                else
                    this.ElementToValidate.Background = new SolidColorBrush(Colors.White);
            }
            ToolTipService.SetToolTip(this.ElementToValidate, this.ValidToolTip);
        }

        #region Виртуальные и абстрактные методы
        protected virtual void Initialize() { }

        public virtual bool Validate()
        {
            bool isValid = ValidateControl();
            if (isValid) ControlValid(); else ControlNotValid();
            return ValidateControl();
        }

        public virtual void ActivateValidationRoutine()
        {
            ElementToValidate.LostFocus += new RoutedEventHandler(ElementToValidate_LostFocus);
            ElementToValidate.KeyUp += new KeyEventHandler(ElementToValidate_KeyUp);
            if (ElementToValidate is Selector)
            {
                (ElementToValidate as Selector).SelectionChanged += new SelectionChangedEventHandler(ValidatorBase_SelectionChanged);
            }
        }

        protected virtual void ValidatorBase_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Dispatcher.BeginInvoke(delegate() { Validate(); });
        }

        protected virtual void ElementToValidate_KeyUp(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke(delegate() { Validate(); });
        }

        protected virtual void ElementToValidate_LostFocus(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke(delegate() { Validate(); });
        }

        public abstract bool ValidateControl();

        public virtual bool IsValid(string str)
        {
            throw new NotImplementedException();
        }

        public virtual bool IsValid(double d)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}